import 'dart:async';

import '../application.dart';
import '../config.dart';
import 'api.dart';
import 'logger.dart';

class Login {
  var isLogging = false;
  var isLogin = false;
  var api = Api.newInstance();

  Completer<bool>? loginComplete;
  Result? result;

  Map<String, dynamic>? userInfo;

  var agent = '';

  var _token = "";
  var _tokenTime = 0;
  var _tokenExpire = 7200;
  var _refreshToken = "";

  var _accessToken = '';

  final _storeKey = 'login_token';

  late Application app;

  Login(this.app, {this.agent = ''});

  Future<void> restoreToken() async {
    try {
      final data = app.spref.get(_storeKey);
      if (data != null && data is List && data.length == 4) {
        logger.info('从缓存恢复登录数据');
        _token = data[0];
        _refreshToken = data[1];
        _tokenTime = int.parse(data[2]);
        _tokenExpire = int.parse(data[3]);
        if (_token.isEmpty ||
            _refreshToken.isEmpty ||
            _tokenExpire <= 0 ||
            _tokenTime <= 0) {
          clearLogin();
          throw Exception('restore token error');
        }
        Api.addHeader('token', _token);
        app.isLogin = true;
        await refresh();
      } else {}
    } catch (_) {
      logger.warning('restore token error', _);
      clearLogin();
      //rethrow;
    }
  }

  saveToken() async {
    if (_token != '') {
      app.spref.setStringList(
        _storeKey,
        [_token, _refreshToken, _tokenTime.toString(), _tokenExpire.toString()],
      );
    }
  }

  String get token => _token;

  clearLogin() async {
    _token = '';
    Api.removeHeader('token');
    app.isLogin = false;
    await app.spref.remove(_storeKey);
  }

  /// 检查登录状态
  Future<bool> checkLogin() async {
    if (isLogging) {
      logger.info('已在登录');

      return await loginComplete!.future;
    }
    if (checkToken()) {
      return true;
    } else {
      return false;
    }
  }

  _checkAccessToken() async {
    if (_accessToken.isEmpty) {
      result = await api.get('auth/token?appid=${Config.appId}');
      if (result!.code == 1) {
        _accessToken = result!.message;
      } else {
        processQueue(success: false);
        throw Exception(result?.message ?? 'Token error');
      }
      logger.info('get token $_accessToken');
    }
    api.addHeader('access_token', _accessToken);
  }

  String urlAddToken(String url) {
    return "$url?access_token=$_accessToken&_t=${DateTime.now().millisecondsSinceEpoch}";
  }

  Future<String> verifyImage() async {
    await _checkAccessToken();
    return '${api.url('auth/captcha')}?access_token=$_accessToken'
        '&_t=${DateTime.now().millisecondsSinceEpoch}';
  }

  Future<Result> sendSMS(String mobile, String captcha, String type) async {
    await _checkAccessToken();
    return await api.post(
      urlAddToken('auth/smscode'),
      {'mobile': mobile, 'captcha': captcha, 'type': type},
    );
  }

  Future<Result> doRegister(Map<String, dynamic> data) async {
    await _checkAccessToken();
    return await api.post(urlAddToken('auth/register'), data);
  }

  Future<Result> doForgot(Map<String, dynamic> data) async {
    await _checkAccessToken();
    return await api.post(urlAddToken('auth/forgot'), data);
  }

  Future<bool> doLogin(username, password, {verify = ''}) async {
    isLogging = true;
    loginComplete = Completer();
    //logger.info('执行登录操作');
    await _checkAccessToken();
    result = await api.post(
      urlAddToken('auth/login'), {'username': username, 'password': password, 'verify': verify},
    );
    //logger.info(result);
    if (result!.code == 1) {
      isLogin = true;
      setLogin(result!.data);

      processQueue();
    } else {
      if (result!.code == 115) {
        _accessToken = '';
        api.removeHeader('access_token');
      }
      processQueue(success: false);
    }
    return await loginComplete!.future;
  }

  /// todo
  Future<dynamic> thirdLogin() {
    return Future(() {});
  }

  /// is_force:是否强制刷新
  Future<bool> refresh({isForce = false}) async {
    if (isLogging) {
      logger.info('已在刷新Token');
      return loginComplete!.future;
    }

    if (isForce || !checkToken()) {
      _token = "";
      Api.removeHeader('token');
      if (_refreshToken != '') {
        logger.info(
          '${isForce ? '强制' : ''}刷新 token  AT ${DateTime.now().toIso8601String()}',
        );
        loginComplete = Completer<bool>();
        isLogging = true;

        result = await api.post(
          'auth/refresh',
          {
            'refresh_token': _refreshToken,
            'scene': 'app',
          },
        );
        if (result!.code == 1) {
          setLogin(result!.data);
          processQueue();
        } else {
          clearLogin();
          processQueue(success: false);
        }

        return loginComplete!.future;
      } else {
        logger.warning('refresh token is empty');
        return checkLogin();
      }
    } else {
      logger.info('不需刷新 token');
      return true;
    }
  }

  /// 检查token是否有效
  bool checkToken() {
    if (_token == '') {
      return false;
    }
    var nowTime = (DateTime.now().millisecondsSinceEpoch / 1000).ceil();
    if (_tokenTime + _tokenExpire - 10 <= nowTime) {
      return false;
    }

    return true;
  }

  /// 设置登录信息
  void setLogin(data) {
    _token = data['token'];
    _tokenTime = (DateTime.now().millisecondsSinceEpoch / 1000).floor();
    _refreshToken = data['refresh_token'];
    _tokenExpire = data['expire_in'];
    Api.addHeader('token', _token);
    app.isLogin = true;
    saveToken();
  }

  void processQueue({bool success = true, Object? error}) {
    logger.info('登录结果回调 $success');
    isLogging = false;
    if (success) {
      _accessToken = '';
      api.removeHeader('access_token');
      loginComplete!.complete(true);
    } else if (result != null) {
      loginComplete!.completeError(ServerException.fromResult(result!));
    } else {
      loginComplete!.completeError(ServerException(500));
    }
  }
}
